The are many ways to test to see if a TCP port is open on another server. Some people use Telnet and some use Powershell cmdlets.

 

Telnet Pros:

  • Legacy application and will work on older version of windows.

Telnet Cons:

  • Telnet is not installed by default, and you must enable this feature.
  • When you get a connection, most of the times you must close the prompt and start a new if you want to try a new one.
  • Slow when it does not get a connection.

Test-NetConnection Pros:

  • Easy to use when doing multiple ports or targets.
  • Built in on server 2012 R2 and newer.

Test-NetConnection Cons:

  • Only available on server 2012 R2 and newer.
  • Slow when it does not get a connection.

 

So what do a mean with “Slow when it does not get a connection”? Well lets check how long it takes it takes for both these commands to timeout.

in powershell to test for telnet.

 Measure-Command -Expression { Start-Process "C:\Windows\System32\telnet.exe" -ArgumentList "192.168.102.1 53" -NoNewWindow -Wait }

And for the Powershell cmdlet.

Measure-Command -Expression { Test-NetConnection -ComputerName 192.168.102.1 -Port 53 -InformationLevel Quiet}

We se that both takes about 21 seconds to execute. So if you have 10 ports to test on 100 servers, and all are closed it will almost take 6 days to test it. That is not a good way to go. Neither of these have a timeout value, so how can we speed it up? Can we use a .Net class? there is a class called TCPClient so lets look at what is has for methods.

 

There we se that we have 2 methods that seem likely (Connect and ConnectAsync), but when we look at them we don´t see any timeout. So lets see if anyone of them has something else we can use.

First we create a TCPObject from the .Net , then instead of just executing the command lets pipe it to get-member.

$TCPObject = new-Object system.Net.Sockets.TcpClient
$TCPObject.Connect("192.168.102.1","53") | get-member

We see that the command Connect does a connection directly (takes long time) before we pipe it, so that we can´t use. Lets check Async. So lets close the connection, create a new and see what ASync gives us.

$TCPObject.Close()
$TCPObject = new-Object system.Net.Sockets.TcpClient
$TCPObject.ConnectAsync("192.168.102.1","53") | get-member

And we have a Method called wait, so what does that use for input?

$TCPObject.ConnectAsync("192.168.102.1","53").wait

Ahh.. it has a Timeout in and in Milliseconds. So lets try it out. We test a connection with timeout 5 seconds.

$TCPObject.ConnectAsync("192.168.102.1","53").wait(5000)

And we get the results False, so closed (or filtered).

The result was quicker then 21 seconds, but did the 5 seconds work? so lest measure it. So close the connection and create a new TCPObject. And the measure the command.

$TCPObject.Close()
$TCPObject = new-Object system.Net.Sockets.TcpClient
Measure-Command -Expression { $TCPObject.ConnectAsync("192.168.102.1","53").wait(5000) }

And we see that is is approx 5 seconds, so it is working.

 

So lets use that in a script.

First we need a function with three inputs, IPAddress(or hostname), Port and the Timeout value. Always remember to close the connection after a test.

Function CheckTCPPortStatus
{
[CmdletBinding()]
Param(
    [Parameter(Mandatory=$True,Position=1)]
    [string]$IPAddress,
    [Parameter(Mandatory=$True,Position=2)]
    [string]$Port,
    [Parameter(Mandatory=$True,Position=3)]
    [int]$Timeout
)
    $TCPObject = new-Object system.Net.Sockets.TcpClient
    if($TCPObject.ConnectAsync($IPAddress,$Port).Wait($Timeout))
    {
        $TCPObject.Close()
        return "Open"
    }
    else
    {
        $TCPObject.Close()
        return "Closed or Filtered"
    }
}

Then we just need to create the script, and call the function.

 

So here is my full script

Test-TCPPort.ps1